from typing import Dict, Optional
import pandas as pd
import numpy as np
from ..config.config import Config

class RiskManager:
    def __init__(self, config: Config):
        self.config = config
        self.position_limits: Dict[str, float] = {}
        self.portfolio_value = config.trading.initial_capital
        self.max_position_size = 0.2  # Maximum 20% of portfolio in single position
        self.stop_loss_pct = 0.02     # 2% stop loss per trade
        self.max_drawdown_limit = 0.15 # 15% maximum drawdown allowed

    def calculate_position_size(
        self,
        symbol: str,
        current_price: float,
        volatility: float,
        available_cash: float
    ) -> float:
        """
        Calculate the position size based on risk parameters
        """
        # Risk amount per trade based on portfolio value
        risk_amount = self.portfolio_value * self.config.trading.risk_per_trade
        
        # Position size based on volatility and stop loss
        position_size = risk_amount / (current_price * volatility)
        
        # Apply position limits
        max_position = available_cash / current_price
        position_size = min(position_size, max_position)
        
        # Apply maximum position size limit
        max_allowed = self.portfolio_value * self.max_position_size / current_price
        position_size = min(position_size, max_allowed)
        
        return float(np.floor(position_size))

    def calculate_stop_loss(
        self,
        entry_price: float,
        position_type: str,
        atr: Optional[float] = None
    ) -> float:
        """
        Calculate stop loss price based on ATR or fixed percentage
        """
        if atr is not None:
            # Use ATR-based stop loss (2 * ATR)
            stop_distance = 2 * atr
        else:
            # Use fixed percentage stop loss
            stop_distance = entry_price * self.stop_loss_pct
        
        if position_type.lower() == 'long':
            return entry_price - stop_distance
        else:
            return entry_price + stop_distance

    def check_portfolio_risk(
        self,
        positions: Dict[str, Dict],
        current_prices: Dict[str, float]
    ) -> Dict[str, bool]:
        """
        Check if current positions comply with risk limits
        """
        total_exposure = 0
        position_risks = {}
        
        for symbol, position in positions.items():
            if symbol not in current_prices:
                continue
                
            current_price = current_prices[symbol]
            position_value = position['size'] * current_price
            total_exposure += position_value
            
            # Check individual position limits
            position_risks[symbol] = {
                'exceeds_size_limit': position_value > (self.portfolio_value * self.max_position_size),
                'stop_loss_triggered': self._check_stop_loss(position, current_price)
            }
        
        # Check overall portfolio exposure
        portfolio_risk = {
            'total_exposure': total_exposure,
            'exposure_ratio': total_exposure / self.portfolio_value,
            'exceeds_portfolio_limit': total_exposure > (self.portfolio_value * 0.8)  # 80% max exposure
        }
        
        return {
            'position_risks': position_risks,
            'portfolio_risk': portfolio_risk
        }

    def _check_stop_loss(self, position: Dict, current_price: float) -> bool:
        """
        Check if stop loss has been triggered for a position
        """
        if position['type'] == 'long':
            return current_price <= position['stop_loss']
        else:
            return current_price >= position['stop_loss']

    def update_portfolio_value(self, new_value: float):
        """
        Update the portfolio value and recalculate risk limits
        """
        self.portfolio_value = new_value
        
    def calculate_value_at_risk(
        self,
        returns: pd.Series,
        confidence_level: float = 0.95,
        time_horizon: int = 1
    ) -> float:
        """
        Calculate Value at Risk (VaR) using historical simulation
        """
        if len(returns) < 100:
            return 0.0
            
        # Calculate VaR
        var_percentile = 1 - confidence_level
        var = np.percentile(returns, var_percentile * 100)
        
        # Scale VaR to time horizon (assuming normal distribution)
        var_t = var * np.sqrt(time_horizon)
        
        return self.portfolio_value * abs(var_t) 